package ciprian.google.parser;

import java.util.ArrayList;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import android.location.Location;
import android.location.LocationManager;
import android.util.Log;

import ciprian.google.Constants;
import ciprian.google.location_mgr.MapPoint;

public class GPXXMLHandler extends DefaultHandler {
    protected final static String TAG = "GPXXMLHandler";

    protected ArrayList<MapPoint> points = new ArrayList<MapPoint>();

    protected Location currentPointLocation;
    protected int currentType;
    protected long currentPointTime;

    protected boolean isEleAvailable;

    @Override
    public void startDocument() throws SAXException {
        // Some sort of setting up work
    }

    @Override
    public void endDocument() throws SAXException {
        // Some sort of finishing up work
    }

    @Override
    public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
            throws SAXException {
        if (localName.equals(Constants.XML_TAG_TRACKPTS)) {
            currentPointLocation = new Location(LocationManager.GPS_PROVIDER);

            currentPointLocation.setLatitude(Double.parseDouble(atts
                    .getValue(Constants.XML_TAG_LATITUDE)));
            currentPointLocation.setLongitude(Double.parseDouble(atts
                    .getValue(Constants.XML_TAG_LONGITUDE)));

            String alt;
            // if we find the 'ele' attribute inside this element read it
            if ((alt = atts.getValue(Constants.XML_TAG_ALTITUDE)) != null)
                currentPointLocation.setAltitude(Double.parseDouble(alt));

            currentType = atts.getValue(Constants.XML_TAG_TYPE) == null ? MapPoint.INTERMEDIATE_POINT
                    : Integer.parseInt(atts.getValue(Constants.XML_TAG_TYPE));

            try {
                currentPointTime = Long.parseLong(atts.getValue(Constants.XML_TAG_TIME));
            } catch (Exception e) {
                // if we can't read the time then don't use it.
                currentPointTime = -1;
            }
            
            currentPointLocation.setTime(currentPointTime);
        } else if (localName.equals(Constants.XML_TAG_ALTITUDE)) {
            String ele = null;
            if ((ele = atts.getValue(Constants.XML_TAG_ALTITUDE)) != null)
                currentPointLocation.setAltitude(Double.parseDouble(ele));
            else
                isEleAvailable = true;
        }
    }

    @Override
    public void characters(char ch[], int start, int length) {
        if (currentPointLocation != null && isEleAvailable) {
            try {
                currentPointLocation.setAltitude(Double.parseDouble(new String(ch, start, length)));
            } catch (Exception e) {
                Log.d(TAG, "Exception thrown, ele to parse = " + new String(ch, start, length));
                e.printStackTrace();
                currentPointLocation.setAltitude(0.00);
            }
            isEleAvailable = false;
        }
    }

    @Override
    public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
        /** set value */
        if (localName.equalsIgnoreCase(Constants.XML_TAG_TRACKPTS) && currentPointLocation != null) {
            MapPoint prevPoint;
            if (currentType != MapPoint.INTERMEDIATE_POINT || points.size() == 0) {
                // this is not an intermediate point or it's the first one
                // ==> add it anyway.
                points.add(new MapPoint(currentType, currentPointLocation));
            } else if ((prevPoint = points.get(points.size() - 1)) != null) {
                Location prevPointLocation = new Location(LocationManager.GPS_PROVIDER);
                prevPointLocation.setLatitude(prevPoint.getLatitude());
                prevPointLocation.setLongitude(prevPoint.getLongitude());

                // if the distance between the last 2 point is smaller than 100m
                // don't add the point.
                if (currentPointLocation.distanceTo(prevPointLocation) > Constants.distanceResolution)
                    points.add(new MapPoint(currentType, currentPointLocation));
            }

            // the current point was added ==> reset the object.
            currentPointLocation = null;
            currentType = MapPoint.INTERMEDIATE_POINT;
        }
    }

    /**
     * @return the points
     */
    public ArrayList<MapPoint> getPoints() {
        return points;
    }
}